#pragma once
#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>

#include <cstring>

const int gbacklog = 5;
class mySocket
{
public:
    // 1.构建tcp socketfd
    static int creatSockfd()
    {
        // 创建socketfd
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        assert(sockfd > 0);
        return sockfd;
    }

    // 2.bind绑定端口
    static void Bind(int sockfd, int port)
    {
        struct sockaddr_in serveraddr;
        memset(&serveraddr, 0, sizeof(serveraddr));
        // 设置地址的信息（协议，ip，端口）
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定任意网卡ip，通常我们访问某一个IP地址是这个服务器的公网网卡IP地址
        serveraddr.sin_port = htons(port);              // 注意端口16位，2字节需要使用htons。不可使用htonl
        if (bind(sockfd, (const sockaddr *)(&serveraddr), sizeof(serveraddr)) < 0)
        {
            perror("sock bind err");
            exit(-1);
        }
        std::cout << "sock bind success" << std::endl;
    }

    // 3. listen监听，让打开的sock这个"文件"去监听来自网络的请求。用于获取新的网络连接
    static void Listen(int sockfd, int n)
    {
        if (listen(sockfd, n) == -1)
        {
            perror("sock listen err");
            exit(-1);
        }
        std::cout << "sock listen success" << std::endl;
    }

    // 4 accept创建sockfd用于传输数据
    static int Accept(int listenfd, std::string &clientIp, uint16_t &clientPort)
    {
        // 获取新fd用于通信
        struct sockaddr_in clientaddr;
        memset(&clientaddr, 0, sizeof(clientaddr));

        socklen_t len = sizeof(clientaddr);
        int sockfd = accept(listenfd, (struct sockaddr *)&clientaddr, &len);

        if (sockfd < 0)
        {
            perror("sock accept err");
            exit(-1);
        }
        else
        {
            // 成功了，可以获取对方的ip和端口
            clientIp = inet_ntoa(clientaddr.sin_addr);
            clientPort = ntohs(clientaddr.sin_port);
        }
        return sockfd;
    }
};
